/* api */
import * as CallCenterApi from '@src/api/CallCenterApi'
/* enum */
import { ZhiChiAgentStateEnum, ZhiChiMessageTypeEnum } from '@model/biz/CallcenterZhichi';
/* model */
import { RESTORE_SUCCESS_MESSAGE } from '@src/model/const/Alert';
/* platform */
import Platform from "@src/platform";
/* util */
import { parseJsonToObject } from '@src/util/lang/object';
import Log from '@src/util/log.ts';
import { getRootWindow } from '@src/util/dom';
import { formatDate } from 'pub-bbx-utils';
import { notificationSuccess } from '@src/platform/message';
/* types */
import { CallCenterZhiChi } from 'types/ZhiChi';
import { isNotUndefined } from '@src/util/type';
import { safeNewDate } from '@src/util/time';

const rootWindow = getRootWindow(window)
const SuccessCode = '000000'

export type CallCenterZhiChiInitCallbackOptionsType = {
  // 开始通话
  onStart?: (result: CallCenterZhiChi.CallbackStartServiceResult) => void
  // 坐席振铃
  onAgentRing?: (result: CallCenterZhiChi.CallbackPhoneStateAgentRingResult) => void
  // 坐席接通
  onAgentConnected?: (result: CallCenterZhiChi.CallbackPhoneStateAgentConnectedResult) => void
  // 用户接通
  onUserConnected?: (result: CallCenterZhiChi.CallbackPhoneStateUserConnectedResult) => void
  // 通话结束
  onStop?: (result: CallCenterZhiChi.CallbackStopServiceResult) => void
}

let initCallbackOptions: CallCenterZhiChiInitCallbackOptionsType = {}

// 通用返回信息
class ZhiChiCommonResult<T extends Record<string, any> | undefined> {
  
  code: string;
  // 消息
  message: string;
  
  data: T | undefined = {} as T;
  
  public get isSuccess(): boolean {
    return this.code == '000000'
  }
  
  public get isError(): boolean {
    return !this.isSuccess
  }
  
  constructor(retCode: string, retMsg: string, data?: T) {
    this.code = retCode
    this.message = retMsg
    this.data = data
  }
  
}

/** 
 * @description 初始化
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-1-%E5%88%9D%E5%A7%8B%E5%8C%96js%E6%8F%92%E4%BB%B6
*/
export function init(initModel: CallCenterZhiChi.InitModel, callbackOptions: CallCenterZhiChiInitCallbackOptionsType = {}): void {
  
  const params = {
    client_id: initModel.clientId,
    client_secret: initModel.clientSecret,
    companyId: initModel.companyId,
    agentId: initModel.agentId,
    // 网络通话
    callWay: 1
  }
  
  Log.info(params, '智齿呼叫中心初始化参数', init.name)
  
  initCallbackOptions = callbackOptions
  
  rootWindow.zcVertoServ.ininServ(params, statusFunc, errorCallBack);
  
}

function statusFunc(result: CallCenterZhiChi.Result<string>) {
  
  let tem: CallCenterZhiChi.StatusResult
  
  if (!result?.data) {
    Log.warn('智齿呼叫中心回调参数数据为空！', statusFunc.name)
    return
  }
  
  tem = parseJsonToObject<CallCenterZhiChi.StatusResult>(result.data)
  
  if (!tem.msgType) {
    Log.warn('智齿呼叫中心回调参数数据 消息类型为空！', statusFunc.name)
    return
  }
  
  Log.info(tem, '智齿呼叫中心回调参数数据', statusFunc.name)
  
  statusFuncImpl(tem)
}

function statusFuncImpl(tem: CallCenterZhiChi.CallbackResult<ZhiChiMessageTypeEnum>): void {
  
  switch (tem.msgType) {
    // 通话开始
    case ZhiChiMessageTypeEnum.StartService: {
      
      const result = tem as CallCenterZhiChi.CallbackResult<ZhiChiMessageTypeEnum.StartService>
      statusStartServiceHandler(result)
      
      break;
    }
    // 坐席响铃
    case ZhiChiMessageTypeEnum.PhoneStateAgentRing: {
      
      const result = tem as CallCenterZhiChi.CallbackResult<ZhiChiMessageTypeEnum.PhoneStateAgentRing>
      statusPhoneStateAgentRingHandler(result)
      
      break;
    }
    // 坐席接通
    case ZhiChiMessageTypeEnum.PhoneStateAgentConnected: {
      
      const result = tem as CallCenterZhiChi.CallbackResult<ZhiChiMessageTypeEnum.PhoneStateAgentConnected>
      statusPhoneStateAgentConnectedHandler(result)
      
      break;
    }
    // 坐席接通
    case ZhiChiMessageTypeEnum.PhoneStateUserConnected: {
      
      const result = tem as CallCenterZhiChi.CallbackResult<ZhiChiMessageTypeEnum.PhoneStateUserConnected>
      statusPhoneStateUserConnectedHandler(result)
      
      break;
    }
    // 通话结束
    case ZhiChiMessageTypeEnum.StopService: {
      
      // @ts-ignore
      const result = tem as CallCenterZhiChi.CallbackResult<ZhiChiMessageTypeEnum.StopService>
      // @ts-ignore
      statusStopServiceHandler(result)
      
      break;
    }
    default: {
      break;
    }
    
  }
}

function errorCallBack(error: unknown | any) {
  
  Platform.notification({
    message: error,
    type: 'error'
  })
  
}

/** 
 * @description 通话开始回调处理
*/
export function statusStartServiceHandler(data: CallCenterZhiChi.CallbackStartServiceResult) {
  initCallbackOptions.onStart?.(data)
  
  const currentAgent = rootWindow.outSideGetAgent()
  const params = {
    ...data,
    agentName: currentAgent.agentName
  }
  
  CallCenterApi.zhiChiCallCenterRecord(params)
}

/** 
 * @description 坐席振铃回调处理
*/
export function statusPhoneStateAgentRingHandler(data: CallCenterZhiChi.CallbackPhoneStateAgentRingResult) {
  initCallbackOptions.onAgentRing?.(data)
  
  const currentAgent = rootWindow.outSideGetAgent()
  const params = {
    ...data,
    ringTime: formatDate(safeNewDate()),
    agentName: currentAgent.agentName
  }
  
  CallCenterApi.zhiChiCallCenterRecord(params)
}

/** 
 * @description 坐席接通回调处理
*/
export function statusPhoneStateAgentConnectedHandler(data: CallCenterZhiChi.CallbackPhoneStateAgentConnectedResult) {
  initCallbackOptions.onAgentConnected?.(data)
  
  const currentAgent = rootWindow.outSideGetAgent()
  const params = {
    ...data,
    beginTime: formatDate(safeNewDate()),
    agentName: currentAgent.agentName
  }
  
  CallCenterApi.zhiChiCallCenterRecord(params)
}

/** 
 * @description 用户接通回调处理
*/
export function statusPhoneStateUserConnectedHandler(data: CallCenterZhiChi.CallbackPhoneStateUserConnectedResult) {
  initCallbackOptions.onUserConnected?.(data)
  
  const currentAgent = rootWindow.outSideGetAgent()
  const params = {
    ...data,
    beginTime: formatDate(safeNewDate()),
    agentName: currentAgent.agentName
  }
  
  CallCenterApi.zhiChiCallCenterRecord(params)
}

/** 
 * @description 通话结束回调处理
*/
export function statusStopServiceHandler(data: CallCenterZhiChi.CallbackStopServiceResult) {
  initCallbackOptions.onStop?.(data)
  
  const currentAgent = rootWindow.outSideGetAgent()
  const params = {
    ...data,
    agentName: currentAgent.agentName
  }
  
  CallCenterApi.zhiChiCallCenterRecord(params)
}

/** 
 * @description 获取token
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-2-%E8%8E%B7%E5%8F%96token
*/
export function getToken(): Promise<string> {
  
  return (
    new Promise<string>((resolve, reject) => {
      rootWindow.zcVertoServ.getToken((result: CallCenterZhiChi.GetTokenResult) => {
        
        Log.info(result, getToken.name, getToken.name)
        
        if (isNotUndefined(result?.expires_in)) {
          
          let expiresSecond = result?.expires_in ?? 0
          let gap = 60 * 60 * 10
          
          expiresSecond = expiresSecond - gap > 0 ? expiresSecond - gap : 0
          
          setTimeout(() => {
            getToken()
          }, expiresSecond * 1000)
          
        }
        
        resolve(result.access_token ?? "")
        
      })
    })
  )
  
}

/** 
 * @description 坐席上班
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-3-%E5%9D%90%E5%B8%AD%E4%B8%8A%E7%8F%AD-%E4%B8%8B%E7%8F%AD
*/
export function agentWork(phone?: string): Promise<ZhiChiCommonResult<undefined>> {
  
  const data = {
    displayNumber: phone,
		isRecordStereo: false,
    // 上班后为空闲状态
		agentState: "1"
  }
  
  return (
    new Promise<ZhiChiCommonResult<undefined>>((resolve, reject) => {
      
      rootWindow.zcVertoServ.agentLogin(data, (result: CallCenterZhiChi.CommonResult) => {
        
        const commonResult = new ZhiChiCommonResult(
          result.retCode, 
          result.retMsg
        ) as ZhiChiCommonResult<undefined>
        
        resolve(commonResult)
        
      })
      
    })
  )
  
}

/** 
 * @description 坐席下班
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-3-%E5%9D%90%E5%B8%AD%E4%B8%8A%E7%8F%AD-%E4%B8%8B%E7%8F%AD
*/
export function agentUnWork(phone?: string): Promise<ZhiChiCommonResult<undefined>> {
  
  return (
    new Promise<ZhiChiCommonResult<undefined>>((resolve, reject) => {
      
      rootWindow.zcVertoServ.agentLoginout((result: CallCenterZhiChi.CommonResult) => {
        
        const commonResult = new ZhiChiCommonResult(
          result.retCode, 
          result.retMsg
        ) as ZhiChiCommonResult<undefined>
        
        resolve(commonResult)
      })
      
    })
  )
  
}

/** 
 * @description 坐席外呼
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-4-%E5%9D%90%E5%B8%AD%E5%A4%96%E5%91%BC
*/
export function agentCallOut(phone: string): Promise<ZhiChiCommonResult<undefined>> {
  
  const data = {
    destinationNumber: phone,
  }
  
  Log.info(data, agentCallOut.name, agentCallOut.name)
  
  return (
    new Promise<ZhiChiCommonResult<undefined>>((resolve, reject) => {
      
      rootWindow.zcVertoServ.agentCallOut(data, (result: CallCenterZhiChi.CommonResult) => {
        
        Log.info(result, agentCallOut.name, agentCallOut.name)
        
        const commonResult = new ZhiChiCommonResult(
          result.retCode, 
          result.retMsg
        ) as ZhiChiCommonResult<undefined>
        
        resolve(commonResult)
      })
      
    })
  )
  
}

/** 
 * @description 坐席挂断
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-5-%E5%9D%90%E5%B8%AD%E6%8C%82%E6%96%AD
*/
export function agentHangUp(callId: string): Promise<ZhiChiCommonResult<undefined>> {
  
  const data = {
    callId
  }
  
  return (
    new Promise<ZhiChiCommonResult<undefined>>((resolve, reject) => {
      
      rootWindow.zcVertoServ.agentHangUp(data, (result: CallCenterZhiChi.CommonResult) => {
        
        const commonResult = new ZhiChiCommonResult(
          result.retCode, 
          result.retMsg
        ) as ZhiChiCommonResult<undefined>
        
        resolve(commonResult)
      })
      
    })
  )
  
}

/** 
 * @description 坐席接听 (网络电话方式接听)
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-6-%E5%9D%90%E5%B8%AD%E6%8E%A5%E5%90%AC-%E7%BD%91%E7%BB%9C%E7%94%B5%E8%AF%9D%E6%96%B9%E5%BC%8F%E6%8E%A5%E5%90%AC
*/
export function agentListen(): Promise<void> {
  
  return (
    new Promise<void>((resolve, reject) => {
      
      rootWindow.zcVertoServ.agentListen()
      
    })
  )
  
}

/** 
 * @description 修改坐席状态
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-7-%E4%BF%AE%E6%94%B9%E5%9D%90%E5%B8%AD%E7%8A%B6%E6%80%81
*/
export function updateAgentState(state: ZhiChiAgentStateEnum): Promise<ZhiChiCommonResult<undefined>> {
  
  return (
    new Promise<ZhiChiCommonResult<undefined>>((resolve, reject) => {
      
      const data = {
        agentState: String(state)
      }
      
      rootWindow.zcVertoServ.updateAgentState(data, (result: CallCenterZhiChi.CommonResult) => {
        
        const commonResult = new ZhiChiCommonResult(
          result.retCode, 
          result.retMsg
        ) as ZhiChiCommonResult<undefined>
        
        resolve(commonResult)
        
      })
      
    })
  )
  
}

/** 
 * @description 查询坐席状态
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-8-%E6%9F%A5%E8%AF%A2%E5%9D%90%E5%B8%AD%E7%8A%B6%E6%80%81
*/
export function queryAgentState(): Promise<ZhiChiCommonResult<CallCenterZhiChi.AgentItem>> {
  
  return (
    new Promise<ZhiChiCommonResult<CallCenterZhiChi.AgentItem>>((resolve, reject) => {
      
      rootWindow.zcVertoServ.queryAgentState((result: CallCenterZhiChi.QueryAgentResult) => {
        
        const commonResult = new ZhiChiCommonResult(
          result.retCode, 
          result.retMsg,
          result.item
        )
        
        resolve(commonResult)
        
      })
      
    })
  )
  
}

/** 
 * @description 重新连接
 * -- 如果查询结坐席果状态不是离线 单独重连
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_6-%E9%A1%B5%E9%9D%A2%E9%87%8D%E8%BD%BD%E6%88%96%E5%88%B7%E6%96%B0%E5%A4%84%E7%90%86%E6%96%B9%E5%BC%8F
*/
export function reConnect(): Promise<void> {
  
  return (
    new Promise<void>((resolve, reject) => {
      
      rootWindow.zcVertoServ.reConnect()
      
    })
  )
  
}

/** 
 * @description 坐席状态重置
 * @see https://www.sobot.com/developerdocs/service/paas_platform_demo.html#_4-17-%E5%9D%90%E5%B8%AD%E7%8A%B6%E6%80%81%E9%87%8D%E7%BD%AE
*/
export function resetStatus(): Promise<void> {
  
  return (
    new Promise<void>((resolve, reject) => {
      
      rootWindow.zcVertoServ.resetStatus((result: CallCenterZhiChi.CommonResult) => {
        
        if (result.retCode == SuccessCode) {
          notificationSuccess(RESTORE_SUCCESS_MESSAGE)
        }
        
        resolve()
      })
      
    })
  )
  
}

export default { 
  init,
  getToken,
  agentWork,
  agentUnWork,
  queryAgentState,
  updateAgentState,
  agentHangUp,
  agentCallOut,
  reConnect,
  agentListen,
  resetStatus
}